/*
File:		Ship.h
Course:		SGD 1301
Author:		Peter Nguyen
Purpose:	CShip class handles the ship entity
*/
#include "Ship.h"
#include <Windows.h>
#include "../SGD Wrappers/CSGD_TextureManager.h"
#include "../SGD Wrappers/CSGD_Direct3D.h"
#include "../SGD Wrappers/CSGD_DirectInput.h"
#include "../SGD Wrappers/SGD_Math.h"
#include "../SGD Wrappers/CSGD_XAudio2.h"
#include "../SGD Wrappers/CSGD_MessageSystem.h"

#include "Message.h"
#include "CreateLaserMessage.h"
#include "CreateSpreadLaserMessage.h"
#include "EntityManager.h"
#include "Game.h"
#include <cassert>

CShip::CShip()
{
	m_eType		= ENT_SHIP;
	m_fSpeed = 0.0f;
	m_fMaxSpeed = 1600;
	m_fRotation = 0.0f;
	m_fCameraRot = 0.0f;
	m_fFireTimer = 0;
	_pervPosX = 0;
	_pervPosY = 0;
	_pervElaspedTime = 0;
	spinOutTimer = 0.0f;
	targetWaypointIndex = -1;
	targetWaypoint = CEntityManager::GetInstance()->GetWayPoint(targetWaypointIndex);
	spinOutVector.fX = 0;
	spinOutVector.fY = 0;
	m_fUnstunableTimer = 0;
}

CShip::~CShip()
{
}

void CShip::SelectNextWayPoint()
{
	if((targetWaypoint.fX-GetPosX()) *(targetWaypoint.fX-GetPosX()) +
		(targetWaypoint.fY-GetPosY()) *(targetWaypoint.fY-GetPosY()) < 450*450)
	{
		targetWaypoint = CEntityManager::GetInstance()->GetWayPoint(targetWaypointIndex);
	}
}

void CShip::Input_Update( float fElapsedTime )
{
	SelectNextWayPoint();

	CSGD_DirectInput* keys = CSGD_DirectInput::GetInstance();
	if(keys->KeyDown(DIK_SPACE) && m_fFireTimer > m_fMaxFireRate)
	{
		m_fFireTimer = 0;

		// Send a CCreateLaserMessage
		CCreateSpreadLaserMessage* pMsg = new CCreateSpreadLaserMessage(this, GetPosX(),GetPosY(),GetRotation());

		CSGD_MessageSystem::GetInstance()->SendMsg( pMsg );
		pMsg = nullptr;
	}
	//turning
	if(keys->KeyDown(DIK_A) || keys->KeyDown(DIK_LEFT))
		m_fRotation += - m_fMaxTurnRate * fElapsedTime;
	else if(keys->KeyDown(DIK_D)|| keys->KeyDown(DIK_RIGHT))
		m_fRotation += m_fMaxTurnRate * fElapsedTime;
	//apply force

	if(keys->KeyDown(DIK_W) || keys->KeyDown(DIK_UP))
		if(m_fSpeed<m_fMaxSpeed)
			m_fSpeed += m_fMaxAcceleration * fElapsedTime;
		else if(keys->KeyDown(DIK_S)|| keys->KeyDown(DIK_DOWN))
			if(m_fSpeed>-m_fMaxSpeed)
				m_fSpeed -= m_fMaxAcceleration * fElapsedTime;
	if(m_fSpeed > m_fMaxSpeed)
		m_fSpeed*=0.999f;
	/*
	if(m_fSpeed > m_fMaxSpeed)
	m_fSpeed = (float)m_fMaxSpeed;
	else if(m_fSpeed < -m_fMaxSpeed)
	m_fSpeed = -(float)m_fMaxSpeed;
	*/
	//move straight forward
	tVector2D forwardVector = {0,-1};
	forwardVector = Vector2DRotate(forwardVector,m_fRotation);

	SetVelX(forwardVector.fX * m_fSpeed);
	SetVelY(forwardVector.fY * m_fSpeed);

	if(CollideWithBound())
	{
		SetVelX(0);
		SetVelY(0);
		SetSpeed(0);
	}
}

void CShip::PowerUp_Update(float fElapsedTime)
{
	//Power up Unstunable
	if(m_fUnstunableTimer>0)
	{
		m_fUnstunableTimer-= fElapsedTime;
		spinOutTimer = 0;
	}
	//Power up Fire rate
	if(m_fFastFireTimer>0)
	{
		m_fFastFireTimer -= fElapsedTime;
		m_fFireTimer+=fElapsedTime*7;
	}
	m_fFireTimer+=fElapsedTime;
}

void CShip::SpinOut(float fElapsedTime)
{
	spinOutTimer-=fElapsedTime;
	m_fRotation+=3.1415f*10*fElapsedTime;
	SetVelX(spinOutVector.fX*200);
	SetVelY(spinOutVector.fY*200);
	if(spinOutTimer<=0)
	{
		SetVelX(0);
		SetVelY(0);
		SetSpeed(0);
	}
}

void CShip::AI_Update( float fElapsedTime )
{
	SelectNextWayPoint();
	//rotate to next waypoint
	if(m_fFireTimer > m_fMaxFireRate)
	{
		m_fFireTimer = 0;

		// Send a CCreateLaserMessage
		CCreateLaserMessage* pMsg = new CCreateLaserMessage(this, GetPosX(),GetPosY(),GetRotation());
		CSGD_MessageSystem::GetInstance()->SendMsg( pMsg );
		pMsg = nullptr;
	}

	tVector2D vOrientation = { 0, -1 };
	vOrientation = Vector2DRotate( vOrientation, m_fRotation );
	tVector2D vToTarget = { };
	vToTarget.fX	= targetWaypoint.fX - this->GetPosX();
	vToTarget.fY	= targetWaypoint.fY - this->GetPosY();
	float fAngle = AngleBetweenVectors( vOrientation, vToTarget );
	float fMaxRotation = (SGD_PI*0.80f) * fElapsedTime;
	if( fAngle > fMaxRotation )
		fAngle = fMaxRotation;
	if( Steering( vOrientation, vToTarget ) < 0 )
		fAngle = -fAngle;
	m_fRotation += fAngle;

	//move straight forward
	tVector2D forwardVector = {0,-1};
	forwardVector = Vector2DRotate(forwardVector,m_fRotation);

	SetVelX(forwardVector.fX * m_fSpeed);
	SetVelY(forwardVector.fY * m_fSpeed);

	if(m_fSpeed<m_fMaxSpeed)
		m_fSpeed+=m_fMaxAcceleration*fElapsedTime;
	else
		m_fSpeed*=0.999f;
	/*
	if(m_fSpeed>m_fMaxSpeed)
	m_fSpeed = m_fMaxSpeed;
	*/
	if(CollideWithBound())
	{
		SetVelX(0);
		SetVelY(0);
		SetSpeed(0);
	}
}

void CShip::Update( float fElapsedTime )
{
	_pervPosX = m_fPosX;
	_pervPosY = m_fPosY;
	_pervElaspedTime = fElapsedTime;
	CEntity::Update(fElapsedTime);
}

void CShip::ApplyDraggingEffect( float fElapsedTime )
{
	tVector2D vOrientation = { 0, -1 };
	vOrientation = Vector2DRotate( vOrientation,  m_fCameraRot);

	tVector2D vTargetRotation = { 0, -1};
	vTargetRotation = Vector2DRotate( vTargetRotation, m_fRotation );

	float fAngle = AngleBetweenVectors(vOrientation,vTargetRotation);

	float fMaxRotation = (SGD_PI*0.50f) * fElapsedTime;
	if( fAngle > fMaxRotation )
		fAngle = fMaxRotation;

	if( Steering(vOrientation,vTargetRotation) < 0 )
		fAngle = -fAngle;

	m_fCameraRot += fAngle;
}

bool CShip::CollideWithBound()
{
	CGame* gamePtr = CGame::GetInstance();
	bool collide = false;
	if(GetPosX()-GetWidth()*0.5f<0)
	{
		SetPosX(GetWidth()*0.5f);
		collide = true;
	}
	else if(GetPosX()+GetWidth()>gamePtr->GetWorldWidth())
	{
		SetPosX((float)(gamePtr->GetWorldWidth()-GetWidth()));
		collide = true;
	}
	if(GetPosY()-GetHeight()*0.5f<0)
	{
		SetPosY(GetHeight()*0.5f);
		collide = true;
	}
	else if(GetPosY()+GetHeight()>gamePtr->GetWorldHeight())
	{
		SetPosY((float)(gamePtr->GetWorldHeight()-GetHeight()));
		collide = true;
	}
	return collide;
}

void CShip::Render( void )
{
	assert( false && "CShip::Render - MAKE AI OR INPUT SHIP NOT REGULAR SHIP" );
}

RECT CShip::GetRect( void ) const
{
	RECT rect = {LONG(GetPosX()-GetWidth()*0.5f),LONG(GetPosY()-GetHeight()*0.5f),
		LONG(GetPosX()+GetWidth()*0.5f),LONG(GetPosY()+GetHeight()*0.5f)};
	return rect;
}

bool CShip::CheckCollision( IEntity* pOther )
{
	RECT rSelf	= this->GetRect();
	RECT rOther	= pOther->GetRect();
	RECT rOverlap;

	if( IntersectRect( &rOverlap, &rSelf, &rOther ) == TRUE )
	{
		if((pOther->GetType()==ENT_INPUTSHIP)||(pOther->GetType()==ENT_AISHIP))
		{
			if(spinOutTimer<=0)
				spinOutTimer = 1.0f;
			CShip* entPtr = (CShip*)pOther;
			float toOther = atan2(entPtr->GetPosY()-GetPosY(),entPtr->GetPosX()-GetPosX());
			spinOutVector.fX = -cos(toOther);
			spinOutVector.fY = -sin(toOther);
			return true;
		}
	}
	return false;
}